package com.wolfking.jeesite.util;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;

import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 操作系统的运行
 */
@Slf4j
public class OsUtils {

    private static ThreadPoolExecutor executor;

    static {
        if (isWindows()) {
            executor = new ThreadPoolExecutor(0, Runtime.getRuntime().availableProcessors(), 1, TimeUnit.SECONDS,
                    new SynchronousQueue<>(), new ThreadFactoryBuilder().setNameFormat("os-util-pool-%d").build(),
                    new ThreadPoolExecutor.CallerRunsPolicy());
            executor.allowCoreThreadTimeOut(true);
        }
    }

    public static boolean isWindows() {
        return System.getProperty("os.name").toUpperCase(Locale.ROOT).startsWith("W") ||
                System.getProperty("os.name").toUpperCase(Locale.ROOT).startsWith("M");
    }

    public static boolean isNotWindows() {
        return !isWindows();
    }


    public static void runWhenWindowsForLimit(int limit, Runnable runnable) {
        runWhenWindowsForLimit(limit, runnable, 0, null);
    }

    public static void runWhenWindowsForLimit(int limit, Runnable runnable, Integer unit, TimeUnit timeUnit) {
        if (isWindows() && executor != null) {
            executor.execute(() -> {
                if (Objects.nonNull(timeUnit) && Objects.nonNull(unit)) {
                    try {
                        timeUnit.sleep(unit);
                    } catch (Exception e) {
                        log.warn("", e);
                    }
                }
                for (int i = 0; i < limit; i++) {
                    try {
                        runnable.run();
                    } catch (Exception e) {
                        log.error("", e);
                    }
                }
            });
        }
    }


    public static void runWhenWindowsSuccessBreakForLimit(int limit, WindowsRunBoolean runnable) {
        runWhenWindowsSuccessBreakForLimit(limit, runnable, -1, null);
    }

    public static void runWhenWindowsSuccessBreakForLimit(int limit, WindowsRunBoolean runnable, Integer unit, TimeUnit timeUnit) {
        if (isWindows() && executor != null) {
            executor.execute(() -> {
                if (Objects.nonNull(timeUnit) && Objects.nonNull(unit)) {
                    try {
                        timeUnit.sleep(unit);
                    } catch (Exception e) {
                        log.warn("", e);
                    }
                }
                for (int i = 0; i < limit; i++) {
                    try {
                        if (runnable.run()) {
                            break;
                        }
                    } catch (Exception e) {
                        log.error("", e);
                    }
                }
            });
        }
    }

    public static <T> T winCondition(T a, T b) {
        return DefUtils.condition(OsUtils::isWindows, a, b);
    }

    @FunctionalInterface
    public interface WindowsRunBoolean {
        boolean run();
    }
}
